package com.cs456.TeamBobcat;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.codec.binary.Base64;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;

public class WebService {
	protected static final String WHERE_AM_I_RESULT_KEY = "where-am-i-result-key";

	protected static final String WHAT_DOES_THIS_SAY_RESULT_KEY = "where-am-i-result-key";

	protected static final String WHAT_DID_THEY_SAY_RESULT_KEY = "what-did-they-say-result-key";

	private static String TAG = "WebService";

	protected static String _serverAddress;

	protected SharedPreferences _prefs;
	protected Context _ctxt;

	public WebService(Context ctxt) {
		_ctxt = ctxt;
		_prefs = PreferenceManager.getDefaultSharedPreferences(_ctxt);
		String address = _prefs.getString(Configuration.SERVER_ADDRESS,
				"127.0.0.1");
		String port = _prefs.getString(Configuration.SERVER_PORT, "3000");

		_serverAddress = "http://" + address + ":" + port + '/';

	}

	// Project Guardian Methods
	// Where Am I? -------------------------------------------------------
	public double[] whereAmI(ArrayList<String> imagePaths) throws Throwable {
		String resp = post("where_am_i_requests", WhereAmIPostXML(imagePaths));
		return parseGPS(resp);
	}

	private double[] parseGPS(String resp) throws Throwable {
		String gpsLatitude = null;
		String gpsLongitude = null;
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		InputSource is = new InputSource();
		is.setCharacterStream(new StringReader(resp));

		Document doc = db.parse(is);
		Element request = (Element) doc.getElementsByTagName(
				"where-am-i-request").item(0);

		NodeList lat = request.getElementsByTagName("latitude");
		Element line = (Element) lat.item(0);
		gpsLatitude = getCharacterDataFromElement(line);

		lat = request.getElementsByTagName("longitude");
		line = (Element) lat.item(0);
		gpsLongitude = getCharacterDataFromElement(line);

		Log.d(TAG, gpsLatitude);
		Log.d(TAG, gpsLongitude);

		double[] ret = { new Double(gpsLatitude), new Double(gpsLongitude) };
		return ret;
	}

	private String WhereAmIPostXML(ArrayList<String> imagePaths)
			throws Throwable {

		String images = "<images>";
		Iterator<String> it = imagePaths.iterator();
		int i = 1;
		while (it.hasNext()) {
			String path = it.next();
			File file = new File(path);
			String name = file.getName();
			Log.d(TAG, path);
			FileInputStream f = new FileInputStream(file);
			int numberBytes = f.available();
			byte data[] = new byte[numberBytes];

			f.read(data);
			f.close();
			String dataString = new String(Base64.encodeBase64(data));
			images += "<image" + i + ">" + "<path>" + path + "</path>"
					+ "<name>" + name + "</name>" + "<data><![CDATA["
					+ dataString + "]]></data>"
					+ "</image" + i + ">";
			i++;
			data = null;
			dataString = null;
			System.gc();
		}
		images += "</images>";

		String ret = "<where-am-i-request>" + "<username>"
				+ _prefs.getString(Configuration.USERNAME, "unknown")
				+ "</username>" + images + "</where-am-i-request>";

		Log.d(TAG, ret);
		return ret;
	}

	// What Did They Say? ------------------------------------------------
	public String whatDidTheySay(String audioFilename) throws Throwable{
		String resp = post("what_did_they_say_requests", WhatDidTheySayXML(audioFilename));
		return parseString(resp, "what-did-they-say-request");
	}

	private String WhatDidTheySayXML(String path) throws Throwable{
		File file = new File(path);
		String name = file.getName();
		Log.d(TAG, path);
		FileInputStream f = new FileInputStream(file);
		int numberBytes = f.available();
		byte data[] = new byte[numberBytes];

		f.read(data);
		f.close();
		String image = 
			"<uploadaudio>" + 
				"<path>" + path + "</path>" + 
				"<name>" + name + "</name>" + 
				"<data><![CDATA[" + new String(Base64.encodeBase64(data)) + "]]></data>" + 
			"</uploadaudio>";
		
		

		String ret = "<what-did-they-say-request>" + "<username>"
				+ _prefs.getString(Configuration.USERNAME, "unknown")
				+ "</username>" + image + "</what-did-they-say-request>";
		data = null;
		System.gc();

		Log.d(TAG, ret);
		return ret;
	}

	// Where Am I? -------------------------------------------------------
	public String whatDoesThisSay(String imgFilename) throws Throwable{
		String resp = post("what_does_this_say_requests", WhatDoesThisSayXML(imgFilename));
		return parseString(resp, "what-does-this-say-request");
	}

	private String parseString(String resp, String resepType) throws Throwable {
		String text = null;
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		InputSource is = new InputSource();
		is.setCharacterStream(new StringReader(resp));

		Document doc = db.parse(is);
		Element request = (Element) doc.getElementsByTagName(
				resepType).item(0);

		NodeList lat = request.getElementsByTagName("translation");
		Element line = (Element) lat.item(0);
		text = getCharacterDataFromElement(line);

		return text;
	}

	private String WhatDoesThisSayXML(String path) throws Throwable {
		File file = new File(path);
		String name = file.getName();
		Log.d(TAG, path);
		FileInputStream f = new FileInputStream(file);
		int numberBytes = f.available();
		byte data[] = new byte[numberBytes];

		f.read(data);
		f.close();
		String image = 
			"<uploadimage>" + 
				"<path>" + path + "</path>" + 
				"<name>" + name + "</name>" + 
				"<data><![CDATA[" + new String(Base64.encodeBase64(data)) + "]]></data>" + 
			"</uploadimage>";
		
		

		String ret = "<what-does-this-say-request>" + "<username>"
				+ _prefs.getString(Configuration.USERNAME, "unknown")
				+ "</username>" + image + "</what-does-this-say-request>";
		data = null;
		System.gc();

		Log.d(TAG, ret);
		return ret;
	}

	// HTTP Methods -----------------------------------------------------------
	// HTTP Get ---------------------------------------------------------------
	private String get(String path) {
		String ret = "";
		try {
			URL url = new URL(_serverAddress + path + ".xml");
			Log.d(TAG, _serverAddress + path + ".xml");
			HttpURLConnection con = (HttpURLConnection) url.openConnection();
			con.setRequestMethod("GET");

			// specify that we will send output and accept input
			con.setDoInput(true);

			// reading the response
			InputStreamReader reader = new InputStreamReader(con
					.getInputStream());

			StringBuilder buf = new StringBuilder();
			char[] cbuf = new char[2048];
			int num;

			while (-1 != (num = reader.read(cbuf))) {
				buf.append(cbuf, 0, num);
			}

			ret = buf.toString();
			System.err.println("\nResponse from server after GET:\n" + ret);
		} catch (MalformedURLException e) {
			Log.d(TAG, "Malformed URL Exception");
			Log.d(TAG, e.getMessage());

		} catch (IOException e) {
			Log.d(TAG, "IO Exception");
			Log.d(TAG, e.getMessage());
		}
		return ret;
	}

	// HTTP Post -------------------------------------------------------------
	private String post(String path, String xmlData) throws Throwable {
		String ret = "";
		URL url = new URL(_serverAddress + path + ".xml");
		HttpURLConnection con = (HttpURLConnection) url.openConnection();
		con.setRequestMethod("POST");

		// specify that we will send output and accept input
		con.setDoInput(true);
		con.setDoOutput(true);

		con.setUseCaches(false);
		con.setDefaultUseCaches(false);

		// tell the web server what we are sending
		con.setRequestProperty("Content-Type", "text/xml");

		OutputStreamWriter writer = new OutputStreamWriter(con
				.getOutputStream());
		writer.write(xmlData);
		writer.flush();
		writer.close();

		// reading the response
		InputStreamReader reader = new InputStreamReader(con.getInputStream());

		StringBuilder buf = new StringBuilder();
		char[] cbuf = new char[2048];
		int num;

		while (-1 != (num = reader.read(cbuf))) {
			buf.append(cbuf, 0, num);
		}

		ret = buf.toString();
		System.err.println("\nResponse Code from server after POST:\n"
				+ con.getResponseCode());
		System.err.println("\nResponse Message from server after POST:\n"
				+ con.getResponseMessage());
		System.err.println("\nResponse from server after POST:\n" + ret);

		return ret;
	}

	private static String getCharacterDataFromElement(Element e) {
		Node child = e.getFirstChild();
		if (child instanceof CharacterData) {
			CharacterData cd = (CharacterData) child;
			return cd.getData();
		}
		return "?";
	}

}
